/*! \file 
	\brief Holds the implementation of the synchronization sub-system. */

#include "kernel.h"
#include "sync.h"

void
initialize_thread_synchronization(void)
{
	LOCK4WRITE(&semaphore_table_lock);
	int i;
	for (i = 0; i < sizeof (semaphore_table) / sizeof (semaphore_table[0]); i++) {
		semaphore_table[i].count = 0;
		semaphore_table[i].owner = -1;
		semaphore_table[i].blocked.head = 0;
		semaphore_table[i].blocked.tail = 0;
	}
	RELEASE_LOCK(&semaphore_table_lock);
	return;
}

void
semaphore_reset(long semaphore_handle)
{
	semaphore_table[semaphore_handle].owner = -1;
	semaphore_table[semaphore_handle].count = 0;
	semaphore_table[semaphore_handle].blocked.head = 0;
	semaphore_table[semaphore_handle].blocked.tail = 0;
	return;
}

int
semaphore_enqueue(int thread_index, long semaphore_handle)
{
	LOCK4WRITE(&semaphore_table_lock);
	const int tail = semaphore_table[semaphore_handle].blocked.tail;
	const int head = semaphore_table[semaphore_handle].blocked.head;
	int report = 0;

	if (tail == MAX_NUMBER_OF_BLOCKED_SEMAPHORE_THREADS - 1) {
		if (head == 0) {
			// The semaphore queue is full, return error.
			report = 1;
		} else {
			semaphore_table[semaphore_handle].blocked.tail = 0;
		}
	} else {
		if (tail + 1 == head) {
			// The semaphore queue is full, return error.
			report = 2;
		} else {
			semaphore_table[semaphore_handle].blocked.tail++;
		}
	}

	if (report == 0) {
		semaphore_table[semaphore_handle].blocked.blocked_threads[tail] = thread_index;
	}
	RELEASE_LOCK(&semaphore_table_lock);
	
	return report;

}

int
semaphore_dequeue(long semaphore_handle)
{
	LOCK4WRITE(&semaphore_table_lock);
	const int tail = semaphore_table[semaphore_handle].blocked.tail;
	const int head = semaphore_table[semaphore_handle].blocked.head;
	int thread_index;

	if (head == tail) { // If the queue is empty, no threads to return and the semaphore should be countet up.
		thread_index = -1;
		semaphore_table[semaphore_handle].count++;
	} else {
		if (head == MAX_NUMBER_OF_BLOCKED_SEMAPHORE_THREADS - 1) {
			semaphore_table[semaphore_handle].blocked.head = 0;
		} else {
			semaphore_table[semaphore_handle].blocked.head++;
		}
		thread_index = semaphore_table[semaphore_handle].blocked.blocked_threads[head];

	}
	RELEASE_LOCK(&semaphore_table_lock);
	
	return thread_index;

}
/* Put any code you need to add to implement assignment 5 here. */
